package lion.framework.core.web.path;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;

import lion.framework.core.web.anno.ViewSpec;
import lion.framework.core.web.request.RequestMethod;
import lion.framework.core.web.views.IView;
import lion.framework.core.web.views.ViewFactory;
import lombok.Getter;
import lombok.Setter;

/**
 * 路径节点,不区分路径大小写
 *
 * <pre>
 * time   2013 2013-4-24 上午11:32:10
 * mail   hl_0074@sina.com
 * </pre>
 *
 * @author lion
 */
public class PathNode {

	public static final Pattern parameterPattern = Pattern.compile("\\{((\\w+):?(\\w+)?)\\}", Pattern.CASE_INSENSITIVE);

	private Map<String, PathNode> pathNodes = new HashMap<>(); // 路径节点

	private Map<String, PathNode> patternNodes = new TreeMap<>(new PathNodeComparator()); // 通配路径节点

	@Getter
	@Setter
	private Method method;
	@Setter
	@Getter
	private Map<String, IView> views = new HashMap<>();
	@Getter
	private Map<String, ViewSpec> viewConfig = new HashMap<>();

	@Getter
	@Setter
	private boolean async = false; // 是否异步
	@Getter
	@Setter
	private boolean singleton = true;// 方法是否单例

	@Getter
	private String pattern;// 路径节匹配正则模式

	@Getter
	private String path = "";// 当前节点

	@Setter
	@Getter
	private String methodType = RequestMethod.ALL.name();// 请求方法类型

	private String pathPatter; // 定义时的路径样式

	public PathNode(String path) {

		this.pathPatter = this.path = path;

		Matcher m = parameterPattern.matcher(path);
		if (!m.find()) { return; }
		m.reset();

		StringBuffer sbu = new StringBuffer();
		while (m.find()) {
			if ("number".equals(m.group(3))) {
				m.appendReplacement(sbu, Matcher.quoteReplacement("(-?\\d+.?\\d*)"));
			} else if ("int".equals(m.group(3))) {
				m.appendReplacement(sbu, Matcher.quoteReplacement("(\\d+)"));
			} else {
				m.appendReplacement(sbu, Matcher.quoteReplacement("([^/]+)"));
			}
		}
		m.appendTail(sbu);
		this.pattern = "(?i)" + sbu.toString();
	}

	/**
	 * 查找请求节点
	 *
	 * @param path
	 *            请求路径
	 */
	public PathNode find(String path) {

		String[] paths = StringUtils.split(path.trim().toLowerCase(), "/");
		if (paths.length == 0) { return null; }
		PathNode current = this;

		for (int i = 0; i < paths.length; i++) {
			String p = paths[i];
			PathNode n = current.pathNodes.get(p);
			if (n == null) {
				for (String key : current.patternNodes.keySet()) {
					PathNode nod = current.patternNodes.get(key);
					if (p.matches(nod.pattern)) {
						n = nod;
						break;
					}
				}
			}
			if (n == null) {
				current = null;
				break;
			}
			if (current.pathNodes.isEmpty() && current.patternNodes.isEmpty()) {
				current = null;
				break;
			}

			current = n;
		}
		return current;

	}

	// 如果节点模式一样，则应当判断为相同节点
	public PathNode add(String pathPatter) {

		String[] paths = StringUtils.split(pathPatter.trim(), "/");

		PathNode n = this;
		for (String path : paths) {
			if (StringUtils.isBlank(path)) {
				continue;
			}
			PathNode node = new PathNode(path);
			n = n.add(node);
		}
		n.pathPatter = pathPatter;
		return n;
	}

	/**
	 * 增加子节点路径 <br/>
	 * 如果两个路径一样，则替换其Method和View
	 */
	private PathNode add(PathNode node) {

		// 查看是否包含 ，如果有包含 ，修改method,view
		PathNode result = node;
		if (node.pattern != null) { // 模式
			PathNode oldNode = this.patternNodes.get(node.pattern);
			if (oldNode != null) {
				// views
				if (node.views != null && !node.views.isEmpty()) {
					oldNode.views = node.views;
				}
				if (node.method != null) {
					oldNode.method = node.method;
				}
				result = oldNode;
			} else {
				this.patternNodes.put(node.pattern, node);
			}
		} else { // 路径直接
			PathNode oldNode = this.pathNodes.get(node.path.toLowerCase());
			if (oldNode != null) {
				// views
				if (node.views != null && !node.views.isEmpty()) {
					oldNode.views = node.views;
				}
				if (node.method != null) {
					oldNode.method = node.method;
				}
				result = oldNode;
			} else {
				this.pathNodes.put(node.path.toLowerCase(), node);
			}
		}

		return result;
	}

	public IView getView(String name) {

		IView view = this.views.get(name);
		if (view == null) {
			ViewSpec vs = this.viewConfig.get(name);
			if (vs != null) {
				view = ViewFactory.createView(vs.getName(), vs.getValue(), vs.getType());
				this.views.put(name, view);
			}
		}
		return view;
	}

	public void addView(String name, String value, String type) {

		this.viewConfig.put(name, new ViewSpec(name, value, type));
	}

	@Override
	public String toString() {

		return this.pathPatter;
	}
}
